package com.zhiche.wms.service.inbound.impl;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.plugins.Page;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import com.google.common.base.Strings;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.zhiche.wms.core.supports.BaseException;
import com.zhiche.wms.core.supports.enums.TableStatusEnum;
import com.zhiche.wms.core.utils.SnowFlakeId;
import com.zhiche.wms.domain.mapper.inbound.InboundNoticeHeaderMapper;
import com.zhiche.wms.domain.mapper.inbound.InboundNoticeLineMapper;
import com.zhiche.wms.domain.model.inbound.InboundNoticeHeader;
import com.zhiche.wms.domain.model.inbound.InboundNoticeLine;
import com.zhiche.wms.domain.model.log.ItfImplogHeader;
import com.zhiche.wms.domain.model.log.ItfImplogLine;
import com.zhiche.wms.dto.inbound.InboundNoticeDTO;
import com.zhiche.wms.dto.inbound.InboundNoticeHeaderDTO;
import com.zhiche.wms.dto.inbound.InboundNoticeLineParamDTO;
import com.zhiche.wms.dto.inbound.InboundNoticeParamDTO;
import com.zhiche.wms.dto.opbaas.paramdto.CommonConditionParamDTO;
import com.zhiche.wms.service.base.IBusinessDocNumberService;
import com.zhiche.wms.service.constant.Status;
import com.zhiche.wms.service.inbound.IInboundNoticeHeaderService;
import com.zhiche.wms.service.inbound.IInboundNoticeLineService;
import com.zhiche.wms.service.log.IItfImplogHeaderService;
import com.zhiche.wms.service.log.IItfImplogLineService;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.*;

/**
 * <p>
 * 入库通知单头 服务实现类
 * </p>
 *
 * @author qichao
 * @since 2018-06-08
 */
@Service
public class InboundNoticeHeaderServiceImpl extends ServiceImpl<InboundNoticeHeaderMapper, InboundNoticeHeader> implements IInboundNoticeHeaderService {

    private Logger logger = (Logger) LoggerFactory.getLogger(getClass());

    @Autowired
    private IInboundNoticeLineService inboundNoticeLineService;
    @Autowired
    private InboundNoticeHeaderMapper noticeHeaderMapper;
    @Autowired
    private InboundNoticeLineMapper noticeLineMapper;
    @Autowired
    private SnowFlakeId snowFlakeId;
    @Autowired
    private IBusinessDocNumberService iBusinessDocNumberService;
    @Autowired
    private IItfImplogHeaderService iItfImplogHeaderService;
    @Autowired
    private IItfImplogLineService iItfImplogLineService;
    @Autowired
    private IInboundNoticeLineService iInboundNoticeLineService;

    @Override
    @Transactional
    public boolean updateStatus(Long noticeId) {
        BigDecimal inboundQty = BigDecimal.ZERO;

        //更新明细入库状态
        inboundNoticeLineService.updateInboundStatus(noticeId);
        EntityWrapper<InboundNoticeLine> ew = new EntityWrapper<>();
        ew.eq("header_id", noticeId);
        List<InboundNoticeLine> inboundNoticeLines = inboundNoticeLineService.selectList(ew);

        for (InboundNoticeLine inboundNoticeLine : inboundNoticeLines) {
            inboundQty = inboundQty.add(inboundNoticeLine.getInboundQty());
        }

        String status = judgeStatus(inboundNoticeLines);
        baseMapper.updateStatus(noticeId, status, inboundQty); //更新头的状态
        return true;
    }

    private String judgeStatus(List<InboundNoticeLine> inboundNoticeLines) {
        Boolean inboundNot = false;
        Boolean inboundAll = false;

        for (InboundNoticeLine inNoticeLine : inboundNoticeLines) {
            if (Status.Inbound.PART.equals(inNoticeLine.getStatus())) { //部分入库直接返回
                return Status.Inbound.PART;
            }

            if (Status.Inbound.NOT.equals(inNoticeLine.getStatus())) {  //未入库
                inboundNot = true;
            }

            if (Status.Inbound.ALL.equals(inNoticeLine.getStatus())) {  //全部入库
                inboundAll = true;
            }
        }

        if (inboundNot && inboundAll) {   //明细中存在未入库和全部入库则返回部分入库
            return Status.Inbound.PART;
        } else if (!inboundNot && inboundAll) { //明细中不存在未入库且全部已入库则返回全部入库
            return Status.Inbound.ALL;
        } else if (inboundNot && !inboundAll) {//明细全部未入库且非全部入库则返回未入库
            return Status.Inbound.NOT;
        }
        return Status.Inbound.NOT;
    }

    /**
     * <p>
     * 更新或者保存通知单数据(更新待确认后进行)
     * </p>
     *
     * @param dtos 参数
     */
    @Override
    public Map<String, Object> saveInboundNotice(List<InboundNoticeParamDTO> dtos) {
        logger.info("InboundNoticeHeaderServiceImpl.saveInboundNotice param:{}", dtos);
        Map<String, Object> exMap = Maps.newHashMap();
        StringBuilder headEx = new StringBuilder();
        StringBuilder lineEx = new StringBuilder();
        if (CollectionUtils.isEmpty(dtos)) {
            headEx.append("参数不能为空");
            exMap.put("headEx", headEx);
        }
        if (exMap.isEmpty()) {
            ArrayList<InboundNoticeHeader> insertHeads = Lists.newArrayList();
            ArrayList<InboundNoticeLine> insertLines = Lists.newArrayList();
            ArrayList<ItfImplogHeader> insertHeadLogs = Lists.newArrayList();
            ArrayList<ItfImplogLine> insertLineLogs = Lists.newArrayList();
            for (int i = 0; i < dtos.size(); i++) {

                InboundNoticeParamDTO dto = dtos.get(i);
                //插入日志
                ItfImplogHeader implogHeader = new ItfImplogHeader();
                implogHeader.setId(snowFlakeId.nextId());
                implogHeader.setDataContent(JSONObject.toJSONString(dto));
                implogHeader.setImportTime(new Date());
                implogHeader.setStatus(TableStatusEnum.STATUS_10.getCode());
                implogHeader.setType(TableStatusEnum.STATUS_10.getCode());
                implogHeader.setUserDef9("interface_saveInboundNoticeHead");
                insertHeadLogs.add(implogHeader);

                checkHead(dto, headEx, i);

                //校验头重复性
                EntityWrapper<InboundNoticeHeader> wrapper = new EntityWrapper<>();
                wrapper.eq("owner_order_no", dto.getOwnerOrderNo())//货主单号
                        .eq("source_key", dto.getSourceKey());//来源唯一键
                Integer count = noticeHeaderMapper.selectCount(wrapper);
                if (count > 0) {
                    headEx.append("第")
                            .append(i + 1)
                            .append("行,已经在wms存在!");
                }
                //保存头
                InboundNoticeHeader header = new InboundNoticeHeader();
                if (StringUtils.isBlank(headEx)) {
                    BeanUtils.copyProperties(dto, header);
                    header.setNoticeNo(iBusinessDocNumberService.getInboundNoticeNo());
                    header.setInboundSumQty(new BigDecimal(0));
                    header.setLogHeaderId(implogHeader.getId());
                    header.setStatus(TableStatusEnum.STATUS_10.getCode());
                    header.setId(snowFlakeId.nextId());
                    insertHeads.add(header);
                } else {
                    exMap.put("headEx", headEx);
                }
                //List<InboundNoticeLineParamDTO> lines = JSONObject.parseArray(detailLines, InboundNoticeLineParamDTO.class);
                List<InboundNoticeLineParamDTO> lines = dto.getLines();
                for (int j = 0; j < lines.size(); j++) {
                    InboundNoticeLineParamDTO lineDTO = lines.get(j);
                    //记录日志line
                    ItfImplogLine implogLine = new ItfImplogLine();
                    implogLine.setId(snowFlakeId.nextId());
                    implogLine.setSeq(String.valueOf(implogLine.getId()));
                    implogLine.setHeaderId(implogHeader.getId());
                    implogLine.setUserDef9("interface_saveInboundNoticeLine");
                    insertLineLogs.add(implogLine);

                    checkLine(lineEx, lineDTO, j);
                    //校验通过
                    if (StringUtils.isBlank(headEx)
                            && StringUtils.isBlank(lineEx)) {
                        //重复性校验
                        EntityWrapper<InboundNoticeLine> lineWrapper = new EntityWrapper<>();
                        lineWrapper.eq("owner_order_no", lineDTO.getLineOwnerOrderNo())//货主单号
                                .eq("lot_no0", lineDTO.getLotNo0())//订单号-->波次
                                .eq("lot_no1", lineDTO.getLotNo1());//车架号
                        Integer lineCount = noticeLineMapper.selectCount(lineWrapper);
                        if (lineCount > 0) {
                            lineEx.append("第:")
                                    .append(j + 1)
                                    .append("行,通知单明细已经在wms存在!");
                        }
                    }
                    if (StringUtils.isNotBlank(lineEx)) {
                        exMap.put("lineEx", lineEx);
                    }
                    //所有校验通过--新增保存
                    if (StringUtils.isBlank(headEx)
                            && StringUtils.isBlank(lineEx)) {
                        InboundNoticeLine line = new InboundNoticeLine();
                        BeanUtils.copyProperties(lineDTO, line);
                        line.setId(snowFlakeId.nextId());
                        line.setHeaderId(header.getId());
                        line.setOwnerId(lineDTO.getLineOwnerId());
                        line.setInboundQty(new BigDecimal(0));
                        line.setOwnerOrderNo(lineDTO.getLineOwnerOrderNo());
                        line.setStatus(TableStatusEnum.STATUS_10.getCode());
                        line.setSeq(String.valueOf(line.getId()));
                        line.setLogLineId(implogLine.getId());
                        insertLines.add(line);
                    }
                }
            }
            //数据插入 日志   业务数据
            insertHeadLog(insertHeadLogs);
            insertLineLog(insertLineLogs);
            //不支持部分保存
            if (exMap.isEmpty()) {
                if (CollectionUtils.isNotEmpty(insertHeads)
                        && CollectionUtils.isNotEmpty(insertLines)) {
                    insertBatch(insertHeads);
                    iInboundNoticeLineService.insertBatch(insertLines);
                }
            }
        }
        return exMap;
    }

    @Override
    @Transactional
    public boolean insertInboundNotice(InboundNoticeHeader inboundNoticeHeader) {
        if (Objects.isNull(inboundNoticeHeader.getId())) inboundNoticeHeader.setId(snowFlakeId.nextId());
        for (InboundNoticeLine inboundNoticeLine : inboundNoticeHeader.getInboundNoticeLineList()) {
            inboundNoticeLine.setHeaderId(inboundNoticeHeader.getId());
            if (Objects.isNull(inboundNoticeLine.getId())) inboundNoticeLine.setId(snowFlakeId.nextId());
        }
        if(CollectionUtils.isEmpty(inboundNoticeHeader.getInboundNoticeLineList())){
            return false;
        }
        return insert(inboundNoticeHeader) &&
                inboundNoticeLineService.insertBatch(inboundNoticeHeader.getInboundNoticeLineList());
    }

    private void insertHeadLog(ArrayList<ItfImplogHeader> insertHeadLogs) {
        if (CollectionUtils.isNotEmpty(insertHeadLogs)) {
            new Thread(() -> {
                try {
                    iItfImplogHeaderService.insertBatch(insertHeadLogs);
                } catch (Exception e) {
                    logger.error("InboundNoticeHeaderServiceImpl.saveInboundNoticeHead insert headLog error:{}", e);
                }
            }).start();
        }
    }

    private void insertLineLog(ArrayList<ItfImplogLine> insertLineLogs) {
        if (CollectionUtils.isNotEmpty(insertLineLogs)) {
            new Thread(() -> {
                try {
                    iItfImplogLineService.insertBatch(insertLineLogs);
                } catch (Exception e) {
                    logger.error("InboundNoticeHeaderServiceImpl.saveInboundNoticeLine insert lineLog error:{}", e);
                }
            }).start();
        }
    }

    private void checkLine(StringBuilder lineEx, InboundNoticeLineParamDTO lineDTO, int j) {
        String lineSourceKey = lineDTO.getLineSourceKey();
        String lineSourceNo = lineDTO.getLineSourceNo();
        String lineOwnerId = lineDTO.getLineOwnerId();
        String lineOwnerOrderNo = lineDTO.getLineOwnerOrderNo();
        BigDecimal expectQty = lineDTO.getExpectQty();
        String lotNo0 = lineDTO.getLotNo0();//订单号
        String lotNo1 = lineDTO.getLotNo1();//车架号
        if (StringUtils.isBlank(lineSourceKey)) {
            lineEx.append("第:")
                    .append(j + 1)
                    .append("行,行来源唯一键 不能为空!");
        }
        if (StringUtils.isBlank(lineSourceNo)) {
            lineEx.append("第:")
                    .append(j + 1)
                    .append("行,行来源单据号 不能为空!");
        }
        if (StringUtils.isBlank(lineOwnerId)) {
            lineEx.append("第:")
                    .append(j + 1)
                    .append("行,货主 不能为空!");
        }
        if (StringUtils.isBlank(lineOwnerOrderNo)) {
            lineEx.append("第:")
                    .append(j + 1)
                    .append("行,货主单号 不能为空!");
        }
        if (Objects.isNull(expectQty)) {
            lineEx.append("第:")
                    .append(j + 1)
                    .append("行,预计入库数量 不能为空!");
        }
        if (StringUtils.isBlank(lotNo0)) {
            lineEx.append("第:")
                    .append(j + 1)
                    .append("行,订单号 不能为空!");
        }
        if (StringUtils.isBlank(lotNo1)) {
            lineEx.append("第:")
                    .append(j + 1)
                    .append("行,车架号 不能为空!");
        }
    }

    private void checkHead(InboundNoticeParamDTO dto,
                           StringBuilder headEx,
                           int i) {
        Long storeHouseId = dto.getStoreHouseId();
        String ownerId = dto.getOwnerId();
        String ownerOrderNo = dto.getOwnerOrderNo();
        BigDecimal expectSumQty = dto.getExpectSumQty();
        String sourceKey = dto.getSourceKey();
        String sourceNo = dto.getSourceNo();
        Integer lineCount = dto.getLineCount();
        String detailLines = dto.getDetailLines();
        if (Objects.isNull(storeHouseId)) {
            headEx.append("第")
                    .append(i + 1)
                    .append("行,收货仓库id 不能为空!");
        }
        if (StringUtils.isBlank(ownerId)) {
            headEx.append("第")
                    .append(i + 1)
                    .append("行,货主id 不能为空!");
        }
        if (StringUtils.isBlank(ownerOrderNo)) {
            headEx.append("第")
                    .append(i + 1)
                    .append("行,货主单号 不能为空!");
        }
        if (Objects.isNull(expectSumQty)) {
            headEx.append("第")
                    .append(i + 1)
                    .append("行,预计入库数量 不能为空!");
        }
        if (StringUtils.isBlank(sourceKey)) {
            headEx.append("第")
                    .append(i + 1)
                    .append("行,来源唯一键 不能为空!");
        }
        if (StringUtils.isBlank(sourceNo)) {
            headEx.append("第")
                    .append(i + 1)
                    .append("行,来源单据号 不能为空!");
        }
        //if (StringUtils.isBlank(detailLines)) {
        //    headEx.append("第")
        //            .append(i + 1)
        //            .append("行,通知单明细 不能为空!");
        //}
        if (Objects.isNull(lineCount)) {
            headEx.append("第")
                    .append(i + 1)
                    .append("行,明细行数 不能为空!");
        }
    }

    /**
     * 查询头list
     *
     */
    public List<InboundNoticeHeaderDTO> selectHeaderList(Long houseId, String status, Integer size, Integer current) {
        try {
            EntityWrapper<InboundNoticeHeaderDTO> ew = new EntityWrapper<>();
            ew.eq("store_house_id", houseId).eq("status", status);
            Page<InboundNoticeHeaderDTO> page = new Page<>(current, size);
            List<InboundNoticeHeaderDTO> inboundNoticeHeaders = this.baseMapper.queryNoticePage(page, ew);
            for (InboundNoticeHeaderDTO inboundNoticeHeader :
                    inboundNoticeHeaders) {
                //修改回传默认值
                if (Objects.isNull(inboundNoticeHeader.getExpectSumQty()))
                    inboundNoticeHeader.setExpectSumQty(new BigDecimal(0));
                if (Objects.isNull(inboundNoticeHeader.getInboundSumQty()))
                    inboundNoticeHeader.setInboundSumQty(new BigDecimal(0));
            }
            return inboundNoticeHeaders;
        } catch (BaseException e) {
            logger.error("Service:\t" + e.toString());
            throw e;
        } catch (Exception e) {
            logger.error("Service:\t" + e.toString());
            throw new BaseException("查询列表出现错误");
        }
    }

    /**
     * 查询包含子单的的头信息
     */
    public InboundNoticeHeaderDTO selectHeaderDeatil(Long houseId, Long id) {
        try {
            EntityWrapper<InboundNoticeHeader> ew = new EntityWrapper<>();
            ew.eq("id", id).eq("store_house_id", houseId);
            //查询头信息
            InboundNoticeHeaderDTO inboundNoticeHeader = this.baseMapper.getNotice(houseId, id);
            if (!Objects.isNull(inboundNoticeHeader)) {
                inboundNoticeHeader.setDriverMess((Strings.isNullOrEmpty(inboundNoticeHeader.getDriverName()) ? "" : inboundNoticeHeader.getDriverName()) + "\t" +
                        (Strings.isNullOrEmpty(inboundNoticeHeader.getDriverPhone()) ? "" : inboundNoticeHeader.getDriverPhone()));
                if (Strings.isNullOrEmpty(inboundNoticeHeader.getDriverName()))
                    inboundNoticeHeader.setDriverName("未登记");
                //获取头信息下的详明信息
                List<InboundNoticeDTO> noticeDTOS = iInboundNoticeLineService.selectInboundByHeadId(inboundNoticeHeader.getId(), houseId);
                //绑定到头中
                inboundNoticeHeader.setInboundNoticeLines(noticeDTOS);
            }
            return inboundNoticeHeader;
        } catch (BaseException e) {
            logger.error("Service:\t" + e.toString());
            throw e;
        } catch (Exception e) {
            logger.error("Service:\t" + e.toString());
            throw new BaseException("查询详情出现错误");
        }
    }
}
